/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package com.eas.client.utils.scalableui;
import com.sun.java.swing.SwingUtilities3;
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Insets;
import java.awt.LayoutManager;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.dnd.DropTarget;
import java.awt.dnd.DropTargetDragEvent;
import java.awt.dnd.DropTargetDropEvent;
import java.awt.dnd.DropTargetEvent;
import java.awt.dnd.DropTargetListener;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.util.HashSet;
import java.util.Iterator;
import java.util.ResourceBundle;
import java.util.Set;
import java.util.TooManyListenersException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.DefaultDesktopManager;
import javax.swing.DesktopManager;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JDesktopPane;
import javax.swing.JInternalFrame;
import javax.swing.JInternalFrame.JDesktopIcon;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollBar;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTree;
import javax.swing.JViewport;
import javax.swing.PopupFactory;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import javax.swing.plaf.ListUI;
import javax.swing.plaf.TableUI;
import javax.swing.plaf.TreeUI;
import javax.swing.text.JTextComponent;
import javax.swing.tree.TreePath;
/**
*
* @author Mg
*/
public class JScalablePanel extends JPanel implements MouseListener, MouseMotionListener, MouseWheelListener, KeyListener, DropTargetListener {
protected AutoScrollTimerTask autoscrollingTask;
protected Timer autoscrollingTimer;
protected DefaultDesktopManager dummyDesktopManager = new DefaultDesktopManager();
protected EventsTargetPanel eventsTarget;
protected DrawWallPanel drawWall;
protected CardLayout cl = new CardLayout();
protected Component dragTarget;
protected Point innerDropTargetPoint;
protected Component innerDropTargetComponent;
protected int enterSelectedIndex = -1;
protected TreePath enterSelectedPath;
protected JScrollPane autoscrollingPane;
protected Point autoscrollingDirection;
protected Component oldInnerDropTarget;
protected Point prevMouseXY;
protected boolean forceHidePopups;
protected Set<ScaleListener> scaleListeners = new HashSet<>();
protected Set<JTextComponent> editingTexts = new HashSet<>();
protected static final float FLOAT_TOLERANCE = 1e-10f;
protected static final float WHEEL_ZOOM_STEP = 0.1f;
protected float SCALE_STEP_VALUE = WHEEL_ZOOM_STEP;
protected static final float ZOOM_MAXIMUM = 1e+10f;
protected static final float ZOOM_MINIMUM = 1e-10f;
protected static final int AUTO_SCROLLING_DELAY = 100;
protected static final int INSET_ZONE = 10;
protected static final String TEXT_COMPS_EDITABLE = "isTextEditable";
protected static final String TEXT_COMPS_BACKGROUND = "TextBackground";
protected static final String TEXT_COMPS_HINT = "TextComponentHint";
public static final String MOUSE_PRESSED_PT_CLIENT_PROPERTY = "mousePressedPt";
protected static final ResourceBundle localizations = ResourceBundle.getBundle("com/eas/client/utils/scalableui/localizations");
protected float autoscrollingVelocityFactor = 3f;
protected static MouseEvent cloneMouseEvent(MouseEvent me, Object source, int eId, Point pt) {
if (source != null && source instanceof Component) {
return new MouseEvent((Component) source, eId, me.getWhen(), me.getModifiers(), pt.x, pt.y, me.getXOnScreen(), me.getYOnScreen(), me.getClickCount(), me.isPopupTrigger(), me.getButton());
} else {
return me;
}
}
protected static MouseWheelEvent cloneMouseWheelEvent(MouseWheelEvent me, Object source, Point pt) {
if (source != null && source instanceof Component) {
return new MouseWheelEvent((Component) source, me.getID(), me.getWhen(), me.getModifiers(), pt.x, pt.y, me.getXOnScreen(), me.getYOnScreen(), me.getClickCount(), me.isPopupTrigger(), me.getScrollType(), me.getScrollAmount(), me.getWheelRotation());
} else {
return me;
}
}
public JScalablePanel() {
super();
setLayout(cl);
autoscrollingTask = new AutoScrollTimerTask();
autoscrollingTimer = new Timer(AUTO_SCROLLING_DELAY, autoscrollingTask);
setOpaque(false);
EventsTargetPanel leventsTarget = new EventsTargetPanel();
drawWall = new DrawWallPanel(leventsTarget);
add(drawWall, DrawWallPanel.class.getSimpleName());
add(leventsTarget, EventsTargetPanel.class.getSimpleName());
eventsTarget = leventsTarget;
drawWall.addMouseListener(this);
drawWall.addMouseMotionListener(this);
drawWall.addMouseWheelListener(this);
if (PopupFactory.getSharedInstance() == null || !(PopupFactory.getSharedInstance() instanceof ScalablePopupFactory)) {
PopupFactory.setSharedInstance(new ScalablePopupFactory(PopupFactory.getSharedInstance()));
}
try {
ScalableTransferHandler sclTHandler = new ScalableTransferHandler(this);
setTransferHandler(sclTHandler);
getDropTarget().addDropTargetListener(this);
} catch (TooManyListenersException ex) {
Logger.getLogger(JScalablePanel.class.getName()).log(Level.SEVERE, null, ex);
}
}
public float getScaleStepValue() {
return SCALE_STEP_VALUE;
}
public void setSCALE_STEP_VALUE(float aStep) {
SCALE_STEP_VALUE = aStep;
if (SCALE_STEP_VALUE <= 0) {
SCALE_STEP_VALUE = 0.2f;
}
}
public void zoomIn() {
scaleBy(SCALE_STEP_VALUE);
}
public void zoomOut() {
scaleBy(-SCALE_STEP_VALUE);
}
@Override
public void setLayout(LayoutManager mgr) {
if (eventsTarget != null) {
eventsTarget.setLayout(mgr);
} else {
super.setLayout(mgr);
}
}
@Override
public Component add(Component comp) {
if (eventsTarget != null) {
return eventsTarget.add(comp);
} else {
return super.add(comp);
}
}
@Override
public Component add(Component comp, int index) {
if (eventsTarget != null) {
return eventsTarget.add(comp, index);
} else {
return add(comp, index);
}
}
@Override
public void add(Component comp, Object constraints) {
if (eventsTarget != null) {
eventsTarget.add(comp, constraints);
} else {
super.add(comp, constraints);
}
}
@Override
public Component add(String name, Component comp) {
if (eventsTarget != null) {
return eventsTarget.add(name, comp);
} else {
return super.add(name, comp);
}
}
@Override
public void add(Component comp, Object constraints, int index) {
if (eventsTarget != null) {
eventsTarget.add(comp, constraints, index);
} else {
super.add(comp, constraints, index);
}
}
@Override
public void updateUI() {
super.updateUI();
checkComponents();
}
protected void checkComponents(JComponent root) {
root.addKeyListener(this);
SwingUtilities3.setDelegateRepaintManager(root, new ZoomRepaintManager());
if (root instanceof JInternalFrame) {
JInternalFrame lIf = (JInternalFrame) root;
if (lIf.getDesktopIcon() != null) {
checkComponents(lIf.getDesktopIcon());
}
}
if (root instanceof JScrollPane) {
JScrollPane scrPane = (JScrollPane) root;
JViewport vport = scrPane.getViewport();
if (vport != null) {
vport.setScrollMode(JViewport.SIMPLE_SCROLL_MODE);
Component view = vport.getView();
if (view instanceof JComponent) {
((JComponent) view).setOpaque(false);
}
}
}
if (root instanceof JComboBox) {
((JComboBox) root).setUI(new ScalableComboUI(((JComboBox) root).getUI()));
}
if (root instanceof JTextComponent) {
JTextComponent tc = (JTextComponent) root;
tc.putClientProperty(TEXT_COMPS_EDITABLE, tc.isEditable());
tc.putClientProperty(TEXT_COMPS_BACKGROUND, tc.getBackground());
tc.putClientProperty(TEXT_COMPS_HINT, tc.getToolTipText());
tc.setEditable(false);
tc.setBackground(Color.lightGray);
tc.setToolTipText(localizations.getString("Click2Edit"));
}
for (int i = 0; i < root.getComponentCount(); i++) {
Component comp = root.getComponent(i);
if (comp instanceof JComponent) {
checkComponents(((JComponent) comp));
}
}
}
public void checkComponents() {
if (eventsTarget != null) {
EventsTargetPanel leventsTarget = eventsTarget;
eventsTarget = null;
try {
checkComponents(leventsTarget);
addKeyListener(this);
drawWall.addKeyListener(this);
} finally {
eventsTarget = leventsTarget;
}
}
}
public void removeAllPopups() {
if (eventsTarget != null) {
for (int i = 0; i < eventsTarget.getComponentCount(); i++) {
if (eventsTarget.getComponent(i) instanceof ScalablePopup.ScalablePopupPanel) {
removeAllPopups((JComponent) eventsTarget.getComponent(i));
}
}
}
}
protected void removeAllPopups(JComponent root) {
if (root instanceof JPopupMenu) {
JPopupMenu lppm = (JPopupMenu) root;
forceHidePopups = true;
try {
lppm.setVisible(false);
} finally {
forceHidePopups = false;
}
} else {
for (int i = root.getComponentCount() - 1; i >= 0; i--) {
Component lcomp = root.getComponent(i);
if (lcomp instanceof JComponent) {
removeAllPopups((JComponent) lcomp);
}
}
}
}
public boolean isForceHidePopups() {
return forceHidePopups;
}
public float getScale() {
if (eventsTarget != null) {
return eventsTarget.getScale();
} else {
return 1f;
}
}
public void fitRectangle(Rectangle aRect, float aScale) {
if (aScale <= 0) {
aScale = 0.1f;
}
Container pCont = getParent();
if (aRect != null && pCont != null && pCont instanceof JViewport) {
JViewport vp = (JViewport) pCont;
Dimension windowSize = vp.getExtentSize();
if (windowSize != null) {
float wF = (float) windowSize.width * aScale / (float) aRect.width;
float hF = (float) windowSize.height * aScale / (float) aRect.height;
float scale = 1;
if (wF < hF) {
scale = wF;
} else {
scale = hF;
}
setScale(scale);
Point center = new Point(Math.round((aRect.x + aRect.width / 2) * scale), Math.round((aRect.y + aRect.height / 2) * scale));
final Rectangle fitRect = new Rectangle(center.x - windowSize.width / 2, center.y - windowSize.height / 2, windowSize.width, windowSize.height);
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
scrollRectToVisible(fitRect);
}
});
}
}
}
public void makeVisible(Rectangle aRect) {
Container pCont = getParent();
if (aRect != null && pCont != null && pCont instanceof JViewport) {
JViewport vp = (JViewport) pCont;
Dimension windowSize = vp.getExtentSize();
if (windowSize != null) {
Point center = new Point(Math.round((aRect.x + aRect.width / 2) * getScale()), Math.round((aRect.y + aRect.height / 2) * getScale()));
final Rectangle fitRect = new Rectangle(center.x - windowSize.width / 2, center.y - windowSize.height / 2, windowSize.width, windowSize.height);
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
scrollRectToVisible(fitRect);
}
});
}
}
}
public boolean isPainting() {
if (eventsTarget != null) {
return eventsTarget.isPainting();
} else {
return false;
}
}
public void scaleBy(float aScale) {
setScale(getScale() + aScale);
}
public void setScale(float aScale) {
if (!isAutoscrollingActive() && (dragTarget == null || dragTarget instanceof JMenuItem)) {
if (Math.abs(aScale) < FLOAT_TOLERANCE) {
aScale = aScale / Math.abs(aScale) * FLOAT_TOLERANCE;
}
if (aScale > ZOOM_MAXIMUM) {
aScale = ZOOM_MAXIMUM;
}
if (aScale < ZOOM_MINIMUM) {
aScale = ZOOM_MINIMUM;
}
eventsTarget.setScale(aScale);
Dimension lpref = eventsTarget.getPreferredSize();
setSize(lpref);
fireScaleChanged();
if (getScale() != 1.0f) {
clearEditingTexts();
}
removeAllPopups();
}
}
public float getAutoscrollingVelocityFactor() {
return autoscrollingVelocityFactor;
}
public void setAutoscrollingVelocityFactor(float factor) {
autoscrollingVelocityFactor = factor;
if (autoscrollingVelocityFactor < 0) {
autoscrollingVelocityFactor = Math.abs(autoscrollingVelocityFactor);
}
if (Math.abs(autoscrollingVelocityFactor) < FLOAT_TOLERANCE) {
autoscrollingVelocityFactor = 2 * FLOAT_TOLERANCE;
}
}
public void addScaleListener(ScaleListener scaleListener) {
if (!scaleListeners.contains(scaleListener)) {
scaleListeners.add(scaleListener);
}
}
public void removeScaleListener(ScaleListener scaleListener) {
scaleListeners.remove(scaleListener);
}
public void fireScaleChanged() {
Iterator<ScaleListener> lit = scaleListeners.iterator();
if (lit != null) {
while (lit.hasNext()) {
ScaleListener sl = lit.next();
sl.scaleChanged(eventsTarget.getOldScale(), eventsTarget.getScale());
}
}
}
protected void clearEditingTexts() {
Iterator<JTextComponent> lit = editingTexts.iterator();
if (lit != null) {
while (lit.hasNext()) {
JTextComponent ltc = lit.next();
ltc.putClientProperty(TEXT_COMPS_EDITABLE, ltc.isEditable());
ltc.putClientProperty(TEXT_COMPS_BACKGROUND, ltc.getBackground());
ltc.putClientProperty(TEXT_COMPS_HINT, ltc.getToolTipText());
ltc.setEditable(false);
ltc.setBackground(Color.lightGray);
ltc.setToolTipText(localizations.getString("Click2Edit"));
if (ltc.getCaret() != null) {
ltc.getCaret().setVisible(false);
}
}
}
editingTexts.clear();
}
public EventsTargetPanel getContentPanel() {
return eventsTarget;
}
public DrawWallPanel getDrawWall() {
return drawWall;
}
protected ScalablePopup.ScalablePopupPanel findPopupPanelAt(Container root, Point pt) {
if (pt == null) {
return null;
}
Point lUnscaledPt = new Point(Math.round(pt.x / getScale()), Math.round(pt.y / getScale()));
Component lfound = findComponentAtXY(root, lUnscaledPt.x, lUnscaledPt.y, false, true, null);
if (lfound instanceof ScalablePopup.ScalablePopupPanel) {
return (ScalablePopup.ScalablePopupPanel) lfound;
}
return null;
}
protected Component findComponentAt(Container root, Point pt) {
if (pt == null) {
return null;
}
Point lUnscaledPt = new Point(Math.round(pt.x / getScale()), Math.round(pt.y / getScale()));
return findComponentAtXY(root, lUnscaledPt.x, lUnscaledPt.y, false, false, null);
}
protected JScrollPane findScrollPaneAt(Container root, Point pt) {
if (pt == null) {
return null;
}
Point lUnscaledPt = new Point(Math.round(pt.x / getScale()), Math.round(pt.y / getScale()));
JScrollPane innerSp = findScrollPaneAtXY(root, lUnscaledPt.x, lUnscaledPt.y, null);
if (innerSp == null) {
Point convertedPt = SwingUtilities.convertPoint(this, pt, root);
while (root != null && (!(root instanceof JScrollPane) || !isInnerInsetPt((JScrollPane) root, convertedPt))) {
root = root.getParent();
convertedPt = SwingUtilities.convertPoint(this, pt, root);
}
if (root instanceof JScrollPane && isInnerInsetPt((JScrollPane) root, convertedPt)) {
return (JScrollPane) root;
}
}
return innerSp;
}
protected static boolean acceptMouseTarget(Component comp) {
return !(comp instanceof JLabel);
}
protected Component findComponentAtXY(Container root, int x, int y, boolean ignoreEnabled, boolean stopAtPopupPanel, Component toExclude) {
synchronized (getTreeLock()) {
if (!(root.contains(x, y) && (ignoreEnabled || root.isEnabled()))) {
return null;
} else if (root.contains(x, y) && stopAtPopupPanel && root instanceof ScalablePopup.ScalablePopupPanel) {
return root;
}
int ncomponents = root.getComponentCount();
Component component[] = root.getComponents();
for (int i = 0; i < ncomponents; i++) {
Component comp = component[i];
if (toExclude == comp) {
continue;
}
if (comp != null && comp.isLightweight()) {
if (comp instanceof Container) {
comp = findComponentAtXY(((Container) comp), x - comp.getX(),
y - comp.getY(), ignoreEnabled, stopAtPopupPanel, toExclude);
} else {
comp = comp.getComponentAt(x - comp.getX(), y - comp.getY());
}
if (comp != null && comp.isVisible()
&& (ignoreEnabled || comp.isEnabled())
&& acceptMouseTarget(comp)) {
return comp;
}
}
}
return root;
}
}
protected JScrollPane findScrollPaneAtXY(Container root, int x, int y, Component toExclude) {
Point lTestPt = new Point(x, y);
synchronized (getTreeLock()) {
if (!root.contains(x, y)) {
return null;
} else if (root.contains(x, y) && root instanceof JScrollPane && isInnerInsetPt((JScrollPane) root, lTestPt)) {
return (JScrollPane) root;
}
int ncomponents = root.getComponentCount();
Component component[] = root.getComponents();
for (int i = 0; i < ncomponents; i++) {
Component comp = component[i];
if (toExclude == comp) {
continue;
}
if (comp != null && comp.isLightweight()) {
if (comp instanceof Container) {
comp = findScrollPaneAtXY(((Container) comp), x - comp.getX(),
y - comp.getY(), toExclude);
} else {
comp = comp.getComponentAt(x - comp.getX(), y - comp.getY());
}
if (comp != null && comp.isVisible()
&& comp instanceof JScrollPane) {
return (JScrollPane) comp;
}
}
}
if (root != null && root.isVisible() && root instanceof JScrollPane && isInnerInsetPt((JScrollPane) root, lTestPt)) {
return (JScrollPane) root;
}
return null;
}
}
@Override
public void mouseClicked(MouseEvent e) {
dragTarget = null;
innerDropTargetComponent = null;
enterSelectedIndex = -1;
enterSelectedPath = null;
cancelAutoScrolling();
Component lc = findComponentAt(eventsTarget, e.getPoint());
if (lc != null) {
componentReleased = lc;
if (lc instanceof JTextComponent && e.getClickCount() > 1) {
JTextComponent tc = (JTextComponent) lc;
Object lPropEditable = tc.getClientProperty(TEXT_COMPS_EDITABLE);
if (lPropEditable != null && lPropEditable instanceof Boolean) {
tc.setEditable((Boolean) lPropEditable);
}
Object lPropBackground = tc.getClientProperty(TEXT_COMPS_BACKGROUND);
if (lPropBackground != null && lPropBackground instanceof Color) {
tc.setBackground((Color) lPropBackground);
}
Object lPropHint = tc.getClientProperty(TEXT_COMPS_HINT);
if (lPropHint == null) {
tc.setToolTipText(null);
}
if (lPropHint != null && lPropHint instanceof String) {
tc.setToolTipText((String) lPropHint);
}
if (tc.isEditable()) {
if (tc.getCaret() != null) {
tc.getCaret().setVisible(true);
}
scaleWithStableMouse(1f / getScale() - 1, e.getPoint());
editingTexts.add(tc);
}
}
Point lpt = convertPoint(e.getPoint(), lc);
MouseListener[] mlisteners = lc.getMouseListeners();
if (mlisteners != null) {
if (componentPressed == componentReleased) {
for (int i = 0; i < mlisteners.length; i++) {
mlisteners[i].mouseClicked(cloneMouseEvent(e, lc, e.getID(), lpt));
}
}
}
}
}
protected void hideCurrentPopup() {
ScalablePopup.ScalablePopupPanel lpnl = (ScalablePopup.ScalablePopupPanel) eventsTarget.getComponent(0);
final JComponent lcont = lpnl.getContents();
if (lcont != null) {
forceHidePopups = true;
try {
lcont.setVisible(false);
} finally {
forceHidePopups = false;
}
}
}
public boolean isTransferHandler(Component aComp) {
return aComp.getDropTarget() != null;
}
public DropTarget getTransferHandler(Component aComp) {
return aComp.getDropTarget();
}
private Component componentPressed = null;
@Override
public void mousePressed(MouseEvent e) {
dragTarget = null;
innerDropTargetComponent = null;
Component lWasOwner = null;
ScalablePopup.ScalablePopupPanel lppm = findPopupPanelAt(eventsTarget, e.getPoint());
if (lppm == null
&& eventsTarget.getComponentCount() > 0
&& eventsTarget.getComponent(0) instanceof ScalablePopup.ScalablePopupPanel) {
ScalablePopup.ScalablePopupPanel lWasppm = (ScalablePopup.ScalablePopupPanel) eventsTarget.getComponent(0);
lWasOwner = lWasppm.getContentsOwner();
hideCurrentPopup();
}
Component lc = findComponentAt(eventsTarget, e.getPoint());
if (lc != null) {
componentPressed = lc;
if(SwingUtilities.isLeftMouseButton(e))
dragTarget = lc;
Point lpt = convertPoint(e.getPoint(), lc);
dragTargetInnerPt = lpt;
MouseListener[] mlisteners = lc.getMouseListeners();
if (mlisteners != null) {
if (lc instanceof JMenuItem) {
for (int i = 0; i < mlisteners.length; i++) {
mlisteners[i].mouseReleased(cloneMouseEvent(e, lc, MouseEvent.MOUSE_RELEASED, lpt));
}
} else {
for (int i = 0; i < mlisteners.length; i++) {
mlisteners[i].mousePressed(cloneMouseEvent(e, lc, e.getID(), lpt));
}
lc.requestFocus();
}
}
if (eventsTarget.getComponentCount() > 0
&& eventsTarget.getComponent(0) instanceof ScalablePopup.ScalablePopupPanel) {
ScalablePopup.ScalablePopupPanel lWasppm = (ScalablePopup.ScalablePopupPanel) eventsTarget.getComponent(0);
Component lNewOwner = lWasppm.getContentsOwner();
if (lNewOwner == lWasOwner) {
hideCurrentPopup();
}
}
}
}
private Component componentReleased = null;
@Override
public void mouseReleased(MouseEvent e) {
cancelAutoScrolling();
Component lc = null;
if (dragTarget != null) {
lc = dragTarget;
}
dragTarget = null;
if (lc == null) {
lc = findComponentAt(eventsTarget, e.getPoint());
}
if (lc != null) {
Point lpt = convertPoint(e.getPoint(), lc);
if (lc instanceof JComponent && SwingUtilities.isRightMouseButton(e)) {
JComponent ljc = (JComponent) lc;
JPopupMenu jpm = ljc.getComponentPopupMenu();
if (jpm != null) {
ljc.putClientProperty(MOUSE_PRESSED_PT_CLIENT_PROPERTY, lpt);
jpm.show(lc, lpt.x, lpt.y);
}
}
MouseListener[] mlisteners = lc.getMouseListeners();
if (mlisteners != null) {
if (lc instanceof JMenuItem) {
for (int i = 0; i < mlisteners.length; i++) {
mlisteners[i].mouseReleased(cloneMouseEvent(e, lc, MouseEvent.MOUSE_RELEASED, lpt));
}
} else {
for (int i = 0; i < mlisteners.length; i++) {
mlisteners[i].mouseReleased(cloneMouseEvent(e, lc, e.getID(), lpt));
}
}
}
}
}
@Override
public void mouseEntered(MouseEvent e) {
prevMouseXY = e.getPoint();
Component lc = findComponentAt(eventsTarget, e.getPoint());
if (lc != null) {
Point lpt = convertPoint(e.getPoint(), lc);
MouseListener[] mlisteners = lc.getMouseListeners();
if (mlisteners != null) {
for (int i = 0; i < mlisteners.length; i++) {
mlisteners[i].mouseEntered(cloneMouseEvent(e, lc, e.getID(), lpt));
}
}
}
}
@Override
public void mouseExited(MouseEvent e) {
cancelAutoScrolling();
prevMouseXY = null;
Component lc = findComponentAt(eventsTarget, e.getPoint());
if (lc != null) {
Point lpt = convertPoint(e.getPoint(), lc);
MouseListener[] mlisteners = lc.getMouseListeners();
if (mlisteners != null) {
for (int i = 0; i < mlisteners.length; i++) {
mlisteners[i].mouseExited(cloneMouseEvent(e, lc, e.getID(), lpt));
}
}
}
}
protected class AutoScrollTimerTask extends Object implements ActionListener {
MouseEvent event = null;
public AutoScrollTimerTask() {
super();
}
public AutoScrollTimerTask(MouseEvent e) {
this();
event = e;
}
public MouseEvent getEvent() {
return event;
}
public void incEvent(Point increment) {
if (event != null) {
Point eventPoint = event.getPoint();
eventPoint.x += increment.x;
eventPoint.y += increment.y;
event = cloneMouseEvent(event, event.getSource(), event.getID(), eventPoint);
}
}
@Override
public void actionPerformed(ActionEvent e) {
autoScrollingStep(this);
}
public void setEvent(MouseEvent e) {
event = e;
}
}
protected JDesktopIcon iifDesktopIcon(Object aSource) {
Component lparent = null;
if (aSource instanceof Component) {
lparent = (Component) aSource;
while (lparent != null && !(lparent instanceof JDesktopIcon)) {
lparent = lparent.getParent();
}
if (lparent != null) {
return (JDesktopIcon) lparent;
}
}
return null;
}
protected JInternalFrame iifInternalFrame(Object aSource) {
Component lparent = null;
if (aSource instanceof Component) {
lparent = (Component) aSource;
while (lparent != null && !(lparent instanceof JInternalFrame)) {
lparent = lparent.getParent();
}
if (lparent != null) {
return (JInternalFrame) lparent;
}
}
return null;
}
protected boolean isAutoscrollingActive() {
return autoscrollingTimer != null && autoscrollingTimer.isRunning();
}
protected Point dragTargetInnerPt = null;
protected void autoScrollingStep(AutoScrollTimerTask asTask) {
if (autoscrollingPane != null && autoscrollingDirection != null && asTask != null) {
JScrollPane lautoscrollingPane = autoscrollingPane;
Component lviewComp = lautoscrollingPane.getViewport().getView();
if (lviewComp instanceof JComponent) {
JComponent lview = (JComponent) lviewComp;
Point lautoscrollingDirection = autoscrollingDirection;
Rectangle viewRect = lautoscrollingPane.getViewport().getViewRect();
Rectangle viewRectBeforeMovement = (Rectangle) viewRect.clone();
viewRect.translate(lautoscrollingDirection.x, lautoscrollingDirection.y);
lview.scrollRectToVisible(viewRect);
Rectangle viewRectAfterMovement = lautoscrollingPane.getViewport().getViewRect();
lautoscrollingDirection.x = viewRectAfterMovement.x - viewRectBeforeMovement.x;
lautoscrollingDirection.y = viewRectAfterMovement.y - viewRectBeforeMovement.y;
if (lautoscrollingDirection.x != 0
|| lautoscrollingDirection.y != 0) {
MouseEvent e = asTask.getEvent();
if (e != null && dragTarget != null) {
JDesktopPane ldp = null;
DesktopManager ldm = null;
JInternalFrame lif = null;
JDesktopIcon ldi = null;
lif = iifInternalFrame(dragTarget);
if (lif != null && lif.getDesktopPane() != null) {
ldp = lif.getDesktopPane();
ldm = ldp.getDesktopManager();
} else {
ldi = iifDesktopIcon(dragTarget);
if (ldi != null && ldi.getDesktopPane() != null) {
ldp = ldi.getDesktopPane();
ldm = ldp.getDesktopManager();
}
}
if (ldp != null && ldm != null && (lif != null || ldi != null)) {
MouseListener[] mlisteners = dragTarget.getMouseListeners();
MouseMotionListener[] mmlisteners = dragTarget.getMouseMotionListeners();
if (mlisteners != null && mmlisteners != null) {
ldp.setDesktopManager(dummyDesktopManager);
try {
for (int i = 0; i < mlisteners.length; i++) {
mlisteners[i].mousePressed(cloneMouseEvent(e, dragTarget, e.getID(), dragTargetInnerPt));
}
} finally {
ldp.setDesktopManager(ldm);
}
asTask.incEvent(lautoscrollingDirection);
MouseEvent afterMoveE = asTask.getEvent();
Point afterMovePt = convertPoint(afterMoveE.getPoint(), dragTarget);
Dimension beforeDragSize = dragTarget.getSize();
int lbeforeWidth = dragTarget.getWidth();
int lbeforeHeight = dragTarget.getHeight();
for (int i = 0; i < mmlisteners.length; i++) {
mmlisteners[i].mouseDragged(cloneMouseEvent(e, dragTarget, e.getID(), afterMovePt));
}
Dimension afterDragSize = dragTarget.getSize();
if (beforeDragSize != null && afterDragSize != null && !beforeDragSize.equals(afterDragSize) && dragTarget != null && dragTarget instanceof JComponent) {
int ldx = afterDragSize.width - beforeDragSize.width;
int ldy = afterDragSize.height - beforeDragSize.height;
JComponent jDragTarget = (JComponent) dragTarget;
Insets insts = jDragTarget.getInsets();
if (dragTargetInnerPt.x >= lbeforeWidth - insts.right) {
dragTargetInnerPt.x += ldx;
}
if (dragTargetInnerPt.y >= lbeforeHeight - insts.bottom) {
dragTargetInnerPt.y += ldy;
}
}
}
}
}
}
} else {
cancelAutoScrolling();
}
}
}
protected Point getInnerInsetPt(JScrollPane testComp, Point aPt) {
Point res = new Point(0, 0);
if (testComp != null && aPt != null) {
int autoscrollZone = Math.round(INSET_ZONE * autoscrollingVelocityFactor);
Rectangle viewRect = autoscrollingPane.getBounds();
JScrollBar vSb = autoscrollingPane.getVerticalScrollBar();
if (vSb != null && vSb.isVisible()) {
viewRect.width -= vSb.getWidth();
}
JScrollBar hSb = autoscrollingPane.getHorizontalScrollBar();
if (hSb != null && hSb.isVisible()) {
viewRect.height -= hSb.getHeight();
}
if (aPt.x > 0 && aPt.x < INSET_ZONE) {
res.x = -autoscrollZone;
} else if (aPt.x > viewRect.width - INSET_ZONE && aPt.x < viewRect.width) {
res.x = autoscrollZone;
}
if (aPt.y > 0 && aPt.y < INSET_ZONE) {
res.y = -autoscrollZone;
} else if (aPt.y > viewRect.height - INSET_ZONE && aPt.y < viewRect.height) {
res.y = autoscrollZone;
}
}
return res;
}
protected boolean isInnerInsetPt(JScrollPane testComp, Point aPt) {
if (testComp == null) {
return false;
}
Rectangle bounds = testComp.getBounds();
bounds.x = 0;
bounds.y = 0;
JScrollBar vSb = testComp.getVerticalScrollBar();
if (vSb != null && vSb.isVisible()) {
bounds.width -= vSb.getWidth();
}
JScrollBar hSb = testComp.getHorizontalScrollBar();
if (hSb != null && hSb.isVisible()) {
bounds.height -= hSb.getHeight();
}
return ((aPt.x > 0 && aPt.x < INSET_ZONE)
|| (aPt.x > bounds.width - INSET_ZONE && aPt.x < bounds.width)
|| (aPt.y > 0 && aPt.y < INSET_ZONE)
|| (aPt.y > bounds.height - INSET_ZONE && aPt.y < bounds.height));
}
protected void cancelAutoScrolling() {
autoscrollingTimer.stop();
autoscrollingPane = null;
}
@Override
public void mouseDragged(MouseEvent e) {
if (e != null) {
cancelAutoScrolling();
Point lcurrPoint = e.getPoint();
Component lprevc = findComponentAt(eventsTarget, prevMouseXY);
Component lcurrentc = findComponentAt(eventsTarget, lcurrPoint);
checkMouseEnterExit(e, lcurrPoint, lprevc, lcurrentc);
JScrollPane llc = findScrollPaneAt(eventsTarget, lcurrPoint);
Component lc = null;
if (dragTarget == null) {
lc = findComponentAt(eventsTarget, e.getPoint());
dragTarget = lc;
} else {
lc = dragTarget;
}
if (lc != null) { // schedule autoscrolling task if needed
if (dragTarget != null && llc != null
&& dragTarget != llc && llc.isAncestorOf(dragTarget)) {
if (llc.getViewport() != null && llc.getViewport().getView() != null) {
Component lviewcomp = llc.getViewport().getView();
if (lviewcomp instanceof JComponent) {
JComponent lview = (JComponent) lviewcomp;
if (lview.getAutoscrolls()) {
Point lMaybeInnerInsetPt = null;
if (isAncestorOf(llc)) {
lMaybeInnerInsetPt = convertPoint(e.getPoint(), llc);
} else {
lMaybeInnerInsetPt = SwingUtilities.convertPoint(this, lcurrPoint, llc);
}
if (isInnerInsetPt(llc, lMaybeInnerInsetPt)
&& !(dragTarget instanceof JScrollBar)) {
autoscrollingPane = llc;
autoscrollingDirection = getInnerInsetPt(llc, lMaybeInnerInsetPt);
autoscrollingTask.setEvent(e);
autoscrollingTimer.start();
}
}
}
}
}
Point lpt = convertPoint(e.getPoint(), lc);
MouseMotionListener[] mlisteners = lc.getMouseMotionListeners();
if (mlisteners != null) {
Dimension beforeDragSize = lc.getSize();
int lbeforeWidth = dragTarget.getWidth();
int lbeforeHeight = dragTarget.getHeight();
//
for (int i = 0; i < mlisteners.length; i++) {
mlisteners[i].mouseDragged(cloneMouseEvent(e, lc, e.getID(), lpt));
}
//
Dimension afterDragSize = lc.getSize();
if (beforeDragSize != null && afterDragSize != null && lc == dragTarget && dragTarget != null && !beforeDragSize.equals(afterDragSize)
&& dragTarget instanceof JComponent) {
int ldx = afterDragSize.width - beforeDragSize.width;
int ldy = afterDragSize.height - beforeDragSize.height;
JComponent jDragTarget = (JComponent) dragTarget;
Insets insts = jDragTarget.getInsets();
if (dragTargetInnerPt.x >= lbeforeWidth - insts.right) {
dragTargetInnerPt.x += ldx;
}
if (dragTargetInnerPt.y >= lbeforeHeight - insts.bottom) {
dragTargetInnerPt.y += ldy;
}
}
}
}
prevMouseXY = lcurrPoint;
}
}
protected void checkMouseEnterExit(MouseEvent e, Point lnewPoint, Component lprevc, Component lc) {
if (lprevc != lc) {
if (lprevc != null) {
Point lpt = convertPoint(lnewPoint, lprevc);
if (!lprevc.contains(lpt)) {
MouseListener[] lprevmml = lprevc.getMouseListeners();
for (int i = 0; i < lprevmml.length; i++) {
lprevmml[i].mouseExited(cloneMouseEvent(e, lprevc, MouseEvent.MOUSE_EXITED, lpt));
}
}
}
if (lc != null) {
Point lpt = convertPoint(lnewPoint, lc);
if (lc.contains(lpt)) {
MouseListener[] lcmml = lc.getMouseListeners();
for (int i = 0; i < lcmml.length; i++) {
lcmml[i].mouseEntered(cloneMouseEvent(e, lc, MouseEvent.MOUSE_ENTERED, lpt));
}
}
}
}
}
@Override
public void mouseMoved(MouseEvent e) {
Point lnewPoint = e.getPoint();
Component lprevc = findComponentAt(eventsTarget, prevMouseXY);
Component lc = findComponentAt(eventsTarget, lnewPoint);
checkMouseEnterExit(e, lnewPoint, lprevc, lc);
if (dragTarget == null) {
if (lc != null) {
Point lpt = convertPoint(lnewPoint, lc);
MouseMotionListener[] mlisteners = lc.getMouseMotionListeners();
if (mlisteners != null) {
for (int i = 0; i < mlisteners.length; i++) {
mlisteners[i].mouseMoved(cloneMouseEvent(e, lc, e.getID(), lpt));
}
}
configureCursor(lc);
if (lc instanceof JComponent) {
JComponent ljc = (JComponent) lc;
String toolTip = ljc.getToolTipText();
drawWall.setToolTipText(toolTip);
} else {
drawWall.setToolTipText(null);
}
}
} else {
cancelAutoScrolling();
}
prevMouseXY = e.getPoint();
}
public void fit() {
Dimension lSize = eventsTarget.getPreferredSize();
lSize.height = Math.round(lSize.height);
lSize.width = Math.round(lSize.width);
JScrollPane lsp = (JScrollPane) getParent().getParent();
Dimension lSpSize = lsp.getSize();
float XScale = (float) lSpSize.width / (float) lSize.width;
float YScale = (float) lSpSize.height / (float) lSize.height;
if (XScale < YScale) {
scaleBy(XScale);
} else {
scaleBy(YScale);
}
}
protected Point calcLeftBottomRes() {
Point lpt = new Point(Integer.MAX_VALUE, Integer.MAX_VALUE);
if (getParent() != null && getParent().getParent() != null
&& getParent().getParent() instanceof JScrollPane) {
JScrollPane lsp = (JScrollPane) getParent().getParent();
Dimension lSpSize = lsp.getSize();
JScrollBar lhsb = lsp.getHorizontalScrollBar();
JScrollBar lvsb = lsp.getVerticalScrollBar();
int lx = 0;
int ly = 0;
if (lhsb != null && lhsb.isVisible()) {
lx = lhsb.getMaximum() - lhsb.getValue() - lSpSize.width;
}
if (lvsb != null && lvsb.isVisible()) {
ly = lvsb.getMaximum() - lvsb.getValue() - lSpSize.height;
}
lpt.x = Math.max(0, lx);
lpt.y = Math.max(0, ly);
}
return lpt;
}
protected void scaleWithStableMouse(float aScalePortion, Point aPt) {
if (aPt != null) {
if (getParent() != null && getParent() instanceof JViewport) {
JViewport lvp = (JViewport) getParent();
Rectangle lOldRect = eventsTarget.getBounds();
Point loldMousePos = convertPoint(aPt, eventsTarget);
Rectangle lbsViewRect = lvp.getViewRect();
// Set scale
scaleBy(aScalePortion);
// Apply scale
Point lvps = lvp.getViewPosition();
lvps.x += 1;
lvp.setViewPosition(lvps);
lvps = lvp.getViewPosition();
lvps.x -= 1;
lvp.setViewPosition(lvps);
Rectangle lNewRect = eventsTarget.getBounds();
Point lnewMousePos = convertPoint(aPt, eventsTarget);
lnewMousePos.x = Math.round((lnewMousePos.x - loldMousePos.x) * getScale());
lnewMousePos.y = Math.round((lnewMousePos.y - loldMousePos.y) * getScale());
if (lNewRect.width < lOldRect.width) {
int lAlreadyMovedX = Math.max(0, lbsViewRect.x + lbsViewRect.width - lNewRect.width);
lnewMousePos.x -= lAlreadyMovedX;
lnewMousePos.x = Math.max(0, lnewMousePos.x);
}
if (lNewRect.height < lOldRect.height) {
int lAlreadyMovedY = Math.max(0, lbsViewRect.y + lbsViewRect.height - lNewRect.height);
lnewMousePos.y -= lAlreadyMovedY;
lnewMousePos.y = Math.max(0, lnewMousePos.y);
}
boolean ldebug = true;
if (ldebug) {
scrollBy(lnewMousePos);
}
} else {
setScale(getScale() + aScalePortion);
}
}
}
protected void scaleWithoutStableMouse(float aScalePortion) {
setScale(getScale() + aScalePortion);
}
protected void setScaleWithoutStableMouse(float aScale) {
setScale(aScale);
}
protected void scrollBy(Point toScrollBy) {
if (toScrollBy != null) {
Rectangle lrt = getVisibleRect();
JScrollPane lsp = null;
if (getParent() != null && getParent().getParent() instanceof JScrollPane) {
lsp = (JScrollPane) getParent().getParent();
if (getParent() instanceof JViewport) {
JViewport lvp = (JViewport) getParent();
lrt = lvp.getViewRect();
}
}
lrt.x -= toScrollBy.x;
lrt.y -= toScrollBy.y;
scrollRectToVisible(lrt);
} else {
toScrollBy = null;
}
}
protected void configureCursor(Component aComp) {
if (!isAutoscrollingActive()) {
if (aComp.isCursorSet()) {
drawWall.setCursor(aComp.getCursor());
} else {
drawWall.setCursor(null);
}
}
}
@Override
public void mouseWheelMoved(final MouseWheelEvent e) {
scaleWithStableMouse(-WHEEL_ZOOM_STEP * e.getWheelRotation(), e.getPoint());
Component lc = findComponentAt(eventsTarget, e.getPoint());
if (lc != null) {
Point lpt = convertPoint(e.getPoint(), lc);
MouseWheelListener[] mlisteners = lc.getMouseWheelListeners();
if (mlisteners != null) {
for (int i = 0; i < mlisteners.length; i++) {
mlisteners[i].mouseWheelMoved(cloneMouseWheelEvent(e, lc, lpt));
}
}
configureCursor(lc);
}
}
protected Point convertPoint(Point point, Component dest) {
return eventsTarget.convertPoint(point, dest);
}
public void setContent(Component aComp) {
eventsTarget.removeAll();
eventsTarget.add(aComp, BorderLayout.CENTER);
checkComponents();
}
@Override
public void keyTyped(KeyEvent e) {
}
@Override
public void keyPressed(KeyEvent e) {
}
@Override
public void keyReleased(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_MULTIPLY) {
fit();
}
}
@Override
public void dragEnter(DropTargetDragEvent dtde) {
Component lc = findComponentAt(eventsTarget, dtde.getLocation());
oldInnerDropTarget = innerDropTargetComponent;
innerDropTargetComponent = lc;
// Save selection on enter
if (innerDropTargetComponent != null) {
if (innerDropTargetComponent instanceof JList) {
JList list = (JList) innerDropTargetComponent;
enterSelectedIndex = list.getSelectedIndex();
}
if (innerDropTargetComponent instanceof JTree) {
JTree tree = (JTree) innerDropTargetComponent;
enterSelectedPath = tree.getSelectionPath();
}
if (innerDropTargetComponent instanceof JTable) {
JTable jTable = (JTable) innerDropTargetComponent;
}
}
// if(lc != null)
// {
// if(lc.getDropTarget() != null)
// {
// Point lpt = convertPoint(dtde.getLocation(), lc);
// lc.getDropTarget().dragEnter(new DropTargetDragEvent(dtde.getDropTargetContext(), lpt, dtde.getDropAction(), dtde.getSourceActions()));
// }
// }
}
@Override
public void dragOver(DropTargetDragEvent dtde) {
cancelAutoScrolling();
Point lnewPoint = dtde.getLocation();
Component lc = findComponentAt(eventsTarget, dtde.getLocation());
oldInnerDropTarget = innerDropTargetComponent;
innerDropTargetComponent = lc;
// Restore selection on enter
if (innerDropTargetComponent != oldInnerDropTarget && oldInnerDropTarget != null) {
if (oldInnerDropTarget instanceof JList) {
JList list = (JList) oldInnerDropTarget;
if (enterSelectedIndex == -1) {
list.clearSelection();
} else {
list.setSelectedIndex(enterSelectedIndex);
}
}
if (oldInnerDropTarget instanceof JTree) {
JTree tree = (JTree) oldInnerDropTarget;
if (enterSelectedPath == null) {
tree.clearSelection();
} else {
tree.setSelectionPath(enterSelectedPath);
}
}
if (oldInnerDropTarget instanceof JTable) {
JTable jTable = (JTable) oldInnerDropTarget;
}
}
// Save selection on enter
if (innerDropTargetComponent != oldInnerDropTarget && innerDropTargetComponent != null) {
if (innerDropTargetComponent instanceof JList) {
JList list = (JList) innerDropTargetComponent;
enterSelectedIndex = list.getSelectedIndex();
}
if (innerDropTargetComponent instanceof JTree) {
JTree tree = (JTree) innerDropTargetComponent;
enterSelectedPath = tree.getSelectionPath();
}
if (innerDropTargetComponent instanceof JTable) {
JTable jTable = (JTable) innerDropTargetComponent;
}
}
// Proceed...
innerDropTargetPoint = convertPoint(dtde.getLocation(), innerDropTargetComponent);
if (innerDropTargetComponent != null && innerDropTargetComponent != dragTarget) {
if (innerDropTargetComponent instanceof JList) {
JList list = (JList) innerDropTargetComponent;
ListUI lui = list.getUI();
int cellIndex2Select = lui.locationToIndex(list, innerDropTargetPoint);
if (cellIndex2Select > -1) {
list.setSelectedIndex(cellIndex2Select);
}
}
if (innerDropTargetComponent instanceof JTree) {
JTree tree = (JTree) innerDropTargetComponent;
TreeUI tui = tree.getUI();
TreePath Path2Select = tui.getClosestPathForLocation(tree, innerDropTargetPoint.x, innerDropTargetPoint.y);
if (Path2Select != null) {
tree.setSelectionPath(Path2Select);
}
}
if (innerDropTargetComponent instanceof JTable) {
JTable jTable = (JTable) innerDropTargetComponent;
TableUI tui = jTable.getUI();
}
}
JScrollPane llc = findScrollPaneAt(eventsTarget, lnewPoint);
/*
String log1 = "";
if(dragTarget != null)
log1 = "dragTarget != null; ";
else
log1 = "dragTarget == null; ";
String log2 = "";
if(llc != null)
log2 = "llc != null";
else
log2 = "llc == null; ";
log1 += log2;
System.out.println(log1);
*/
// schedule autoscrolling task if needed
if (dragTarget != null && dragTarget != llc && llc instanceof JScrollPane) {
Point lMaybeInnerInsetPt = null;
if (isAncestorOf(llc)) {
lMaybeInnerInsetPt = convertPoint(lnewPoint, llc);
} else {
lMaybeInnerInsetPt = SwingUtilities.convertPoint(this, lnewPoint, llc);
}
if (llc.getViewport() != null && llc.getViewport().getView() != null) {
Component lviewcomp = llc.getViewport().getView();
if (lviewcomp instanceof JComponent) {
JComponent lview = (JComponent) lviewcomp;
if (lview.getAutoscrolls()) {
if (isInnerInsetPt(llc, lMaybeInnerInsetPt)
&& !(dragTarget instanceof JScrollBar)) {
autoscrollingPane = llc;
autoscrollingDirection = getInnerInsetPt(llc, lMaybeInnerInsetPt);
autoscrollingTask.setEvent(null);
autoScrollingStep(autoscrollingTask);
autoscrollingTimer.start();
}
}
}
}
}
}
@Override
public void dropActionChanged(DropTargetDragEvent dtde) {
}
@Override
public void dragExit(DropTargetEvent dte) {
oldInnerDropTarget = null;
innerDropTargetComponent = null;
//dragTarget = null; - need to stay old value - to save autoscrolling fuctionality
}
@Override
public void drop(DropTargetDropEvent dtde) {
oldInnerDropTarget = null;
innerDropTargetComponent = null;
dragTarget = null;
}
public Component getInnerDropTargetComponent() {
return innerDropTargetComponent;
}
public Point getInnerDropTargetPoint() {
return innerDropTargetPoint;
}
}